/*********************************************************************************/
/*                                                                               */
/*      GPT Driver                                                               */
/*                                                                               */
/*      Last updated by:   CBS                                                   */
/*      Last update date:  2013/1/25                                             */
/*      Revision:          0                                                     */
/*      Copyright:         DENS0                                                 */
/*                                                                               */
/*********************************************************************************/

/*********************************************************************************/
/*  include files                                                                */
/*********************************************************************************/
#include "MPC5674F_MVx264.h"
#include "Gpt.h"
#include "INTCInterrupts.h"

/*********************************************************************************/
/*  prototypes                                                                   */
/*********************************************************************************/
static void Det_ReportError(U2 ModuleId, U1 InstanceId, U1 ApiId, U1 ErrorId);
static void GPT_RTI_ISR_Response( void );
static void Gpt_PIT_ISR_Channel1( void );
static void Gpt_PIT_ISR_Channel2( void ); 
static void Gpt_PIT_ISR_Channel3( void ); 
static void Gpt_PIT_ISR_Channel4( void ); 

/*********************************************************************************/
/*  defines  / macros                                                            */
/*********************************************************************************/
#if ( GPT_DEV_ERROR_DETECT == STD_ON )

   #define VALIDATE(_exp,_api,_err)                      \
     if( !(_exp) )                                       \
     {                                                   \
        Det_ReportError(MODULE_ID_GPT,0,_api,_err);      \
        return;                                          \
     }
     
   #define VALIDATE_W_RV(_exp,_api,_err,_rv )            \
     if( !(_exp) )                                       \
     {                                                   \
        Det_ReportError(MODULE_ID_GPT,0,_api,_err);      \
        return (_rv);                                    \
     }
        
   #define VALID_CHANNEL(_ch)	( Gpt_Global.configured & (1<<(_ch)) )

#else

   #define VALIDATE(_exp,_api,_err)
   #define VALIDATE_W_RV(_exp,_api,_err,_rv)
   
#endif

/*********************************************************************************/
/*  constants / data types / structs / unions                                    */
/*********************************************************************************/
/* Moudule version information */
#if (GPT_VERSION_INFO_API == STD_ON)
static Std_VersionInfoType GPT_VersionInfoPtr =
{  
    GPT_VENDOR_ID, 
	GPT_MODULE_ID,
	GPT_INSTANCE_ID,
	GPT_SW_MAJOR_VERSION,
	GPT_SW_MINOR_VERSION,
	GPT_SW_PATCH_VERSION,
	GPT_AR_MAJOR_VERSION,
	GPT_AR_MINOR_VERSION,
	GPT_AR_PATCH_VERSION 
};
#endif

/* Type that holds all global data for Gpt */
typedef struct
{
  boolean  initRun;                     /* flag to be set if Gpt_Init() have been called */
  const Gpt_ConfigType *config;         /* Our config */
  U1  wakeupEnabled;
  U4  configured;                       /*One bit for each channel that is configured.Used to determine if validity of a channel*/
                                        /* 1 - configured, 0 - NOT configured */
  U1  channelMap[GPT_CHANNEL_CNT];      /* Maps the a channel id to a configured channel id */
} Gpt_GlobalType;

/* Type that holds data specifically for a channel */
typedef struct
{
  Gpt_StateType state;
} Gpt_UnitType;

/* Time channel state array */
Gpt_UnitType Gpt_Unit[GPT_CHANNEL_CNT];

/* Global config */
Gpt_GlobalType Gpt_Global;

/*********************************************************************************/
/*  API Functions                                                                */
/*********************************************************************************/

/************************************************************************************************************************/
/*  Service name        :   Gpt_Init                                                                                    */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   Pointer to a selected configuration structure                                               */
/*  Return value        :   None                                                                                        */
/*  Discription         :   Initializes the hardware timer module                                                       */
/************************************************************************************************************************/
void Gpt_Init (const Gpt_ConfigType *ConfigPtr)
{
  U1 i = 0;
  Gpt_ChannelType ch;
  const Gpt_ConfigType *cfg;
  
  VALIDATE( (Gpt_Global.initRun == STD_OFF), GPT_INIT_SERVICE_ID, GPT_E_ALREADY_INITIALIZED );/*GPT307*/
  VALIDATE( (ConfigPtr != NULL ), GPT_INIT_SERVICE_ID, GPT_E_PARAM_CONFIG );/*GPT294,GPT340*/

  for (; i<GPT_CHANNEL_CNT; i++)
  {
    Gpt_Global.channelMap[i] = GPT_CHANNEL_ILL;
  }

  i = 0;
  cfg = ConfigPtr;
 
  while (cfg->GptChannelId != GPT_CHANNEL_ILL)
  {
    ch = cfg->GptChannelId;

    /* Assign the configuration channel for later use.*/
    Gpt_Global.channelMap[cfg->GptChannelId] = i;
    Gpt_Global.configured |= (1<<ch);

    if (ch <= GPT_CHANNEL_CNT)
    {
      if (cfg->GptNotification != NULL)
      {
        switch( ch )
        {
          case 0: INTC_InstallINTCInterruptHandler( GPT_RTI_ISR_Response,INTC_RTI_VectorNum,  cfg->GptNotificationPriority ); break;
          case 1: INTC_InstallINTCInterruptHandler( Gpt_PIT_ISR_Channel1,INTC_PIT1_VectorNum, cfg->GptNotificationPriority ); break;
          case 2: INTC_InstallINTCInterruptHandler( Gpt_PIT_ISR_Channel2,INTC_PIT2_VectorNum, cfg->GptNotificationPriority ); break;
          case 3: INTC_InstallINTCInterruptHandler( Gpt_PIT_ISR_Channel3,INTC_PIT3_VectorNum, cfg->GptNotificationPriority ); break;
          case 4: INTC_InstallINTCInterruptHandler( Gpt_PIT_ISR_Channel4,INTC_PIT4_VectorNum, cfg->GptNotificationPriority ); break;        
          default: break;/* Unknown PIT channel.*/
        }
      }
    }
    else
    {
      
    }

    cfg++;
    i++;
  }
  
  Gpt_Global.config = ConfigPtr;

  Gpt_Global.initRun = STD_ON;
  PIT.MCR.B.MDIS = 0;
}



/************************************************************************************************************************/
/*  Service name        :   Gpt_DeInit                                                                                  */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   None                                                                                        */
/*  Return value        :   None                                                                                        */
/*  Discription         :   Deinitializes all hardware timer channels                                                   */
/************************************************************************************************************************/
#if GPT_DEINIT_API == STD_ON/*GPT194*/

void Gpt_DeInit(void)
{
  Gpt_ChannelType channel;
  VALIDATE( (Gpt_Global.initRun == STD_ON), GPT_DEINIT_SERVICE_ID, GPT_E_UNINIT );/*GPT220*/
  /* Validate that all channels have been stopped */
  for (channel = 0; channel < GPT_CHANNEL_CNT; channel++) 
  {
    if(!(Gpt_Unit[channel].state == GPT_STATE_STOPPED))/*GPT234*/
    {
        Det_ReportError(MODULE_ID_GPT,0,GPT_DEINIT_SERVICE_ID,GPT_E_BUSY);
        Gpt_StopTimer(channel);
    }
  }
  Gpt_Global.initRun = STD_OFF;
  Gpt_Global.configured = NULL;
}
#endif



/************************************************************************************************************************/
/*  Service name        :   Gpt_StartTimer                                                                              */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   Channel    Numeric identifier of the GPT channel                                            */
/*                          Value      Target time in number of ticks                                                   */
/*  Return value        :   None                                                                                        */
/*  Discription         :   Starts a timer channel                                                                      */
/************************************************************************************************************************/

void Gpt_StartTimer(Gpt_ChannelType channel, Gpt_ValueType period_ticks)
{
  U1 confCh;

  VALIDATE( (Gpt_Global.initRun == STD_ON), GPT_STARTTIMER_SERVICE_ID, GPT_E_UNINIT );
  VALIDATE( VALID_CHANNEL(channel), GPT_STARTTIMER_SERVICE_ID, GPT_E_PARAM_CHANNEL );
  VALIDATE( (Gpt_Unit[channel].state == GPT_STATE_STOPPED), GPT_STARTTIMER_SERVICE_ID, GPT_E_BUSY );

  confCh = Gpt_Global.channelMap[channel];

  if (channel <= GPT_CHANNEL_CNT)
  {
    if(channel == GPT_CHANNEL_RTI)
    {
       PIT.RTI.LDVAL.R = period_ticks;
       PIT.RTI.CVAL.R = period_ticks; 
       
       /* Make sure that no interrupt is pending */
       PIT.RTI.TFLG.B.TIF = 1;
    
       /* always select interrupt */
       PIT.RTI.TCTRL.B.TIE = 1;
    
       /* Enable RTI timer */
       PIT.RTI.TCTRL.B.TEN = 1;   
    }
    
    else
    {
       PIT.CH[channel-1].LDVAL.R = period_ticks;
       PIT.CH[channel-1].CVAL.R = period_ticks;  
    
       /* Make sure that no interrupt is pending */
       PIT.CH[channel-1].TFLG.B.TIF = 1;
    
       /* always select interrupt */
       PIT.CH[channel-1].TCTRL.B.TIE = 1;
    
       /* Enable PIT timer */
       PIT.CH[channel-1].TCTRL.B.TEN = 1;  
    }

  }
  else
  {
    
  }

  if( Gpt_Global.config[confCh].GptNotification != NULL )
  {
    /* GPT275 */
    PIT.CH[channel-1].TCTRL.B.TIE = 1;  
  }

  Gpt_Unit[channel].state = GPT_STATE_STARTED;   
}


/************************************************************************************************************************/
/*  Service name        :   Gpt_StopTimer                                                                               */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   Channel    Numeric identifier of the GPT channel                                            */
/*  Return value        :   None                                                                                        */
/*  Discription         :   Stops a timer channel                                                                       */
/************************************************************************************************************************/

void Gpt_StopTimer(Gpt_ChannelType channel)
{

  VALIDATE( (Gpt_Global.initRun == STD_ON), GPT_STOPTIMER_SERVICE_ID, GPT_E_UNINIT );
  VALIDATE( VALID_CHANNEL(channel), GPT_STOPTIMER_SERVICE_ID, GPT_E_PARAM_CHANNEL );

  if (channel <= GPT_CHANNEL_CNT)
  {
    if(channel == GPT_CHANNEL_RTI)
    {
  	   /* Disable RTI timer */
  	   PIT.RTI.TCTRL.B.TEN = 0;
    }
    
    /* Disable PIT timer */
    PIT.CH[channel-1].TCTRL.B.TEN = 0;
  }
  else
  {
   
  }

  Gpt_Unit[channel].state = GPT_STATE_STOPPED;
}


/************************************************************************************************************************/
/*  Service name        :   Gpt_GetTimeRemaining                                                                        */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   Channel    Numeric identifier of the GPT channel                                            */
/*  Return value        :   Gpt_ValueType     Remaining timer value (in number of ticks)                                */
/*  Discription         :   Returns the time remaining until the target time is reached                                 */
/************************************************************************************************************************/

#if ( GPT_TIME_REMAINING_API == STD_ON )

Gpt_ValueType Gpt_GetTimeRemaining(Gpt_ChannelType channel)
{
  Gpt_ValueType remaining;
  
  VALIDATE_W_RV( (Gpt_Global.initRun == STD_ON), GPT_GETTIMEREMAINING_SERVICE_ID, GPT_E_UNINIT, 0 );
  VALIDATE_W_RV( VALID_CHANNEL(channel),GPT_GETTIMEREMAINING_SERVICE_ID, GPT_E_PARAM_CHANNEL, 0 );
  VALIDATE_W_RV( (Gpt_Unit[channel].state == GPT_STATE_STARTED), GPT_GETTIMEREMAINING_SERVICE_ID, GPT_E_NOT_STARTED, 0 );

  
  if (channel <= GPT_CHANNEL_CNT)
  {
    if(channel == GPT_CHANNEL_RTI)
    {
  	   remaining = PIT.RTI.CVAL.R;
    }
    
    /* Time remaining is the time until it hits 0, so just return the current timer value.*/
    remaining = PIT.CH[channel-1].CVAL.B.TVL;
  }
  else
  {
    /* We have written a fault in the fault log. Return 0. */
    remaining = 0;
  }

  return remaining;
}
#endif


/************************************************************************************************************************/
/*  Service name        :   Gpt_GetTimeElapsed                                                                          */
/*  Sync/Async          :   Synchronous                                                                                 */
/*  Reentrancy          :   Non Reentrant                                                                               */
/*  Parameters (in)     :   Channel    Numeric identifier of the GPT channel                                            */
/*  Return value        :   Gpt_ValueType     Elapsed timer value (in number of ticks)                                  */
/*  Discription         :   Returns the time already elapsed                                                            */
/************************************************************************************************************************/

#if ( GPT_TIME_ELAPSED_API == STD_ON )

Gpt_ValueType Gpt_GetTimeElapsed(Gpt_ChannelType channel)
{
  Gpt_ValueType elapse;

  VALIDATE_W_RV( (Gpt_Global.initRun == STD_ON), GPT_GETTIMEELAPSED_SERVICE_ID, GPT_E_UNINIT ,0 );
  VALIDATE_W_RV( VALID_CHANNEL(channel),GPT_GETTIMEELAPSED_SERVICE_ID, GPT_E_PARAM_CHANNEL, 0 );
  VALIDATE_W_RV( (Gpt_Unit[channel].state == GPT_STATE_STARTED),GPT_GETTIMEELAPSED_SERVICE_ID, GPT_E_NOT_STARTED, 0 );

  if (channel <= GPT_CHANNEL_CNT)
  {
    if(channel == GPT_CHANNEL_RTI)
    {
  	   elapse = PIT.RTI.LDVAL.R - PIT.RTI.CVAL.R;
    }
    
    elapse = PIT.CH[channel-1].LDVAL.B.TSV - PIT.CH[channel-1].CVAL.B.TVL;
  }
  else
  {
    /* We have written a fault in the fault log. Return 0. */
    elapse = 0;
  }

  return elapse;
}
#endif

/************************************************************************************************************************/
/*	Service name        :	Gpt_GetVersionInfo                                                                          */
/*	Sync/Async          :	Synchronous                                                                                 */
/*	Reentrancy          :	Reentrant                                                                                   */
/*	Parameters (out)    :   VersionInfoPtr      Pointer to where to store the version information of this module.       */
/*	Return value        :	None                                                                                        */
/*	Description	        : 	Returns the version information of this module.                                             */
/************************************************************************************************************************/
#if (GPT_VERSION_INFO_API == STD_ON) /*GPT273*/

void Gpt_GetVersionInfoPtr(Std_VersionInfoType* VersionInfoPtr)
{
   VersionInfoPtr->vendorID = GPT_VersionInfoPtr.vendorID;
   VersionInfoPtr->moduleID = GPT_VersionInfoPtr.moduleID;
   VersionInfoPtr->instanceID = GPT_VersionInfoPtr.instanceID;
	  
   VersionInfoPtr->sw_major_version = GPT_VersionInfoPtr.sw_major_version;
   VersionInfoPtr->sw_minor_version = GPT_VersionInfoPtr.sw_minor_version;
   VersionInfoPtr->sw_patch_version = GPT_VersionInfoPtr.sw_patch_version;
	  
   VersionInfoPtr->ar_major_version = GPT_VersionInfoPtr.ar_major_version;
   VersionInfoPtr->ar_minor_version = GPT_VersionInfoPtr.ar_minor_version;
   VersionInfoPtr->ar_patch_version = GPT_VersionInfoPtr.ar_patch_version;
   
   VALIDATE( (VersionInfoPtr != NULL ), GPT_INIT_SERVICE_ID, GPT_E_PARAM_CONFIG );/*GPT338*/
}
#endif





/*********************************************************************************/
/*  Local Functions                                                              */
/*********************************************************************************/

void Det_ReportError(U2 ModuleId, U1 InstanceId, U1 ApiId, U1 ErrorId)
{
	/* error report! */
}


/* ISR for a given RTI channel,mainly for system wakeup interrupt. */
void GPT_RTI_ISR_Response(void)
{
  /* service for ISR,be implemented by the user. */
}


/* ISR for a given PIT channel (macro),and we can modify it according to our needs. */
#define GPT_PIT_ISR_Response(_channel)                 \
  static void Gpt_PIT_ISR_Channel##_channel(void)      \
  {                                                    \
    const Gpt_ConfigType *config;                      \
    U1 confCh;                                         \
    /* Find the config entry for the PIT channel.*/    \
    confCh = Gpt_Global.channelMap[_channel];          \
    config = &Gpt_Global.config[confCh];               \
    if(config->GptChannelMode == GPT_MODE_ONESHOT)     \
    {                                                  \
       /* Disable the channel.*/                       \
       PIT.CH[_channel-1].TCTRL.B.TEN=0;               \
       Gpt_Unit[_channel].state = GPT_STATE_STOPPED;   \
    }                                                  \
    /* Notification for need.*/                        \
    config->GptNotification();                         \
                                                       \
    /* Clear interrupt. */                             \
    PIT.CH[_channel-1].TFLG.B.TIF=1;                   \
  }

/* Create instances of the ISR for each PIT channel.*/

GPT_PIT_ISR_Response(1)
GPT_PIT_ISR_Response(2)
GPT_PIT_ISR_Response(3)
GPT_PIT_ISR_Response(4)

 
 
 
 /*-- End Of File -------------------------------------------------------*/